package com.person.tablelayoutmanager;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 实现表格布局
 */
public class TableLayoutManager extends RecyclerView.LayoutManager {

    private static final String TAG = TableLayoutManager.class.getSimpleName();

    /**
     * 构建器
     */
    private Build mBuild;
    /**
     * state
     */
    private LayoutState mLayoutState;

    private TableLayoutManager(Build build) {
        mBuild = build;
        mLayoutState = new LayoutState();
    }

    //生成默认的布局参数 一般情况下不需要去动它
    //如果需要存储一些额外的东西在LayoutParams里，这里返回你自定义的LayoutParams即可。
    //当然，你自定义的LayoutParams需要继承自RecyclerView.LayoutParams
    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
        return new LayoutParams(c, attrs);
    }

    @Override
    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
        if (lp instanceof ViewGroup.MarginLayoutParams) {
            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
        } else {
            return new LayoutParams(lp);
        }
    }

    @Override
    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
        return lp instanceof LayoutParams;
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);
        if (getItemCount() <= 0 || state.isPreLayout() || mBuild.mColumnCount <= 0) {
            return;
        }
        Log.d(TAG, "onLayoutChildren gogogogogogogogogogo");
        mLayoutState.reset();
        mLayoutState.mColumnCount = mBuild.mColumnCount;
        //确定总共有多少行
        mLayoutState.mRowCount = getItemCount() % mBuild.mColumnCount == 0 ? getItemCount() / mBuild.mColumnCount : getItemCount() / mBuild.mColumnCount + 1;
        //内容显示区域(可滑动的区域)
        mLayoutState.mSlideAreaRect.set(0, 0, getHorizontalActiveWidth(), getVerticalActiveHeight());
        Log.d(TAG, "-----------------------------------------------------------------------------------------------------");
        Log.d(TAG, getHorizontalActiveWidth() + "");
        Log.d(TAG, getVerticalActiveHeight() + "");
        Log.d(TAG, mLayoutState.mSlideAreaRect.top + "");
        Log.d(TAG, mLayoutState.mSlideAreaRect.bottom + "");
        Log.d(TAG, mLayoutState.mSlideAreaRect.left + "");
        Log.d(TAG, mLayoutState.mSlideAreaRect.right + "");
        Log.d(TAG, "-----------------------------------------------------------------------------------------------------");

        // 先移除所有view  这里是因为onLayoutChildren会回调两次，避免size*2
        detachAndScrapAttachedViews(recycler);
        //计算平铺出来的宽度和高度
        calculateSpreadSize(recycler);
        //真正的layout
        fillChildren(recycler, state);
    }

    @SuppressLint("LongLogTag")
    private void fillChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getItemCount() <= 0 || state.isPreLayout()) {
            return;
        }

        Log.d(TAG, "start fill children");
        Rect itemRect = new Rect();
        int rowStart = getDisplayRowStart();//获取要显示行开始的位置
        int rowEnd = getDisplayRowEnd();//获取要显示行结束的位置
        int columnStart = getDisplayColumnStart();//获取显示列开始的位置
        int columnEnd = getDisplayColumnEnd();//获取显示列结束的位置
        int preRowHeight = getPreRowHeight(rowStart);//获取指定行前面的高度
        Log.d(TAG, "********************************************************************************************");
        Log.d(TAG, "rowStart = " + rowStart);
        Log.d(TAG, "rowEnd = " + rowEnd);
        Log.d(TAG, "columnStart = " + columnStart);
        Log.d(TAG, "columnEnd = " + columnEnd);
        Log.d(TAG, "preRowHeight = " + preRowHeight);
        Log.d(TAG, "********************************************************************************************");
        for (int row = rowStart; row <= rowEnd; row++) {
            int preColumnWidth = getPreColumnWidth(columnStart);//获取指定列前面的宽度
            for (int column = columnStart; column <= columnEnd; column++) {
                boolean skip = false;
                //计算当前item pos
                int position = row * mBuild.mColumnCount + column;
                if (row == mLayoutState.mRowCount - 1 && position >= getItemCount()) {
                    break;
                }
                //重置rect  如果需要固定表头 并且当前正在表头位置  则有如下计算
                //itemRect就是可滑动区域的 矩阵
                if (mBuild.mFixHeader && row == 0) {
                    itemRect.set(preColumnWidth, preRowHeight, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column),
                            preRowHeight + mBuild.mHeadHeight);
                } else {
                    itemRect.set(preColumnWidth, preRowHeight, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column),
                            preRowHeight + mBuild.mRowHeight);
                }

                //处理固定不动的tag
                if (mBuild.mFixHeader && row == 0) {
                    skip = true;
                }
                if (column < mBuild.mFixColumnCount) {
                    skip = true;
                }
                if (!skip && Rect.intersects(mLayoutState.mSlideAreaRect, itemRect)) {
                    Log.d(TAG,"asdasdasdasdasdsadsadasdasdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
                    Log.d(TAG,"pos = "+ position);
                    View view = recycler.getViewForPosition(position);
                    addView(view);
                    final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                    if (mBuild.mFixHeader) {
                        layoutParams.height = row == 0 ? mBuild.mHeadHeight : mBuild.mRowHeight;
                    } else {
                        layoutParams.height = mBuild.mRowHeight;
                    }
                    layoutParams.width = mLayoutState.mEachColumnWidthList.get(column);
                    measureChildWithMargins(view, 0, 0);
                    layoutDecoratedWithMargins(view, itemRect.left - mLayoutState.mOffsetHorizontal,
                            itemRect.top - mLayoutState.mOffsetVertical, itemRect.right - mLayoutState.mOffsetHorizontal,
                            itemRect.bottom - mLayoutState.mOffsetVertical);
                }
                preColumnWidth += mLayoutState.mEachColumnWidthList.get(column);
            }
            if (mBuild.mFixHeader && row == 0) {
                preRowHeight += mBuild.mHeadHeight;
            } else {
                preRowHeight += mBuild.mRowHeight;
            }
        }
        /**
         * 处理列固定
         */
        preRowHeight = getPreRowHeight(rowStart);//获取指定行前面的高度  重新赋值
        if (mBuild.mFixColumnCount > 0) {
            for (int row = rowStart; row <= rowEnd; row++) {
                int preColumnWidth = 0;
                for (int column = 0; column < mBuild.mFixColumnCount; column++) {
                    boolean skip = false;
                    int position = row * mBuild.mColumnCount + column;
                    if (row == mLayoutState.mRowCount - 1 && position >= getItemCount()) {
                        break;
                    }
                    if (mBuild.mFixHeader && row == 0) {
                        itemRect.set(preColumnWidth, preRowHeight, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column),
                                preRowHeight + mBuild.mHeadHeight);
                    } else {
                        itemRect.set(preColumnWidth, preRowHeight, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column),
                                preRowHeight + mBuild.mRowHeight);
                    }
                    if (mBuild.mFixHeader && row == 0) {
                        skip = true;
                    }
                    if (!skip) {
                        View view = recycler.getViewForPosition(position);
                        addView(view);
                        final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                        if (mBuild.mFixHeader) {
                            layoutParams.height = row == 0 ? mBuild.mHeadHeight : mBuild.mRowHeight;
                        } else {
                            layoutParams.height = mBuild.mRowHeight;
                        }
                        layoutParams.width = mLayoutState.mEachColumnWidthList.get(column);
                        measureChildWithMargins(view, 0, 0);
                        layoutDecoratedWithMargins(view, itemRect.left, itemRect.top - mLayoutState.mOffsetVertical, itemRect.right,
                                itemRect.bottom - mLayoutState.mOffsetVertical);
                    }
                    preColumnWidth += mLayoutState.mEachColumnWidthList.get(column);
                }
                if (mBuild.mFixHeader && row == 0) {
                    preRowHeight += mBuild.mHeadHeight;
                } else {
                    preRowHeight += mBuild.mRowHeight;
                }
            }
        }
        /**
         * 处理行固定，有固定的时候也是固定第一行
         */
        if (mBuild.mFixHeader) {
            int preColumnWidth = getPreColumnWidth(columnStart);
            for (int column = columnStart; column <= columnEnd; column++) {
                boolean skip = false;
                if (column >= getItemCount()) {
                    break;
                }
                itemRect.set(preColumnWidth, 0, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column), mBuild.mHeadHeight);
                if (column < mBuild.mFixColumnCount) {
                    skip = true;
                }
                if (!skip) {
                    View view = recycler.getViewForPosition(column);
                    addView(view);
                    final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                    layoutParams.height = mBuild.mHeadHeight;
                    layoutParams.width = mLayoutState.mEachColumnWidthList.get(column);
                    measureChildWithMargins(view, 0, 0);
                    layoutDecoratedWithMargins(view, itemRect.left - mLayoutState.mOffsetHorizontal, itemRect.top,
                            itemRect.right - mLayoutState.mOffsetHorizontal, itemRect.bottom);
                }
                preColumnWidth += mLayoutState.mEachColumnWidthList.get(column);
            }
        }

        /**
         * 处理固定行固定列相交的部分
         */
        if (mBuild.mFixHeader && mBuild.mFixColumnCount > 0) {
            int preColumnWidth = 0;
            for (int column = 0; column < mBuild.mFixColumnCount; column++) {
                if (column >= getItemCount()) {
                    break;
                }
                itemRect.set(preColumnWidth, 0, preColumnWidth + mLayoutState.mEachColumnWidthList.get(column), mBuild.mHeadHeight);
                View view = recycler.getViewForPosition(column);
                addView(view);
                final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                layoutParams.height = mBuild.mHeadHeight;
                layoutParams.width = mLayoutState.mEachColumnWidthList.get(column);
                measureChildWithMargins(view, 0, 0);
                layoutDecoratedWithMargins(view, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
                preColumnWidth += mLayoutState.mEachColumnWidthList.get(column);
            }
        }

        Log.d(TAG, "end fill children");
    }

    /**
     * 获取指定行前面的高度
     */
    private int getPreRowHeight(int row) {
        int preRowHeight = 0;
        for (int index = 0; index < row; index++) {
            if (mBuild.mFixHeader && index == 0) {
                preRowHeight += mBuild.mHeadHeight;
            } else {
                preRowHeight += mBuild.mRowHeight;
            }
        }
        return preRowHeight;
    }

    /**
     * 获取指定列前面的宽度
     */
    private int getPreColumnWidth(int column) {
        if (mLayoutState.mEachColumnWidthList == null || mLayoutState.mEachColumnWidthList.size() == 0) {
            return 0;
        }
        int preColumnWidth = 0;
        for (int index = 0; index < column; index++) {
            preColumnWidth += mLayoutState.mEachColumnWidthList.get(index);
        }
        return preColumnWidth;
    }

    /**
     * 获取要显示行开始的位置
     */
    private int getDisplayRowStart() {
        int rowHeightPre = 0;
        for (int row = 0; row < mLayoutState.mRowCount; row++) {
            int itemBottom;
            //是否固定表头
            if (mBuild.mFixHeader && row == 0) {
                itemBottom = rowHeightPre + mBuild.mHeadHeight;
            } else {
                itemBottom = rowHeightPre + mBuild.mRowHeight;
            }
            if (itemBottom > mLayoutState.mSlideAreaRect.top) {
                return row;
            }
            if (mBuild.mFixHeader && row == 0) {
                rowHeightPre += mBuild.mHeadHeight;
            } else {
                rowHeightPre += mBuild.mRowHeight;
            }
        }
        return 0;
    }

    /**
     * 获取要显示行结束的位置
     */
    private int getDisplayRowEnd() {
        int rowHeightPre = 0;
        for (int row = 0; row < mLayoutState.mRowCount; row++) {
            int itemTop = rowHeightPre;
            if (itemTop >= mLayoutState.mSlideAreaRect.bottom) {
                return row;
            }
            if (mBuild.mFixHeader && row == 0) {
                rowHeightPre += mBuild.mHeadHeight;
            } else {
                rowHeightPre += mBuild.mRowHeight;
            }
        }

        return mLayoutState.mRowCount - 1;
    }

    /**
     * 获取显示列开始的位置
     */
    private int getDisplayColumnStart() {
        int columnPre = 0;
        for (int column = 0; column < mLayoutState.mEachColumnWidthList.size(); column++) {
            int itemRight = columnPre + mLayoutState.mEachColumnWidthList.get(column);
            if (itemRight > mLayoutState.mSlideAreaRect.left) {
                return column;
            }
            columnPre += mLayoutState.mEachColumnWidthList.get(column);
        }
        return 0;
    }

    /**
     * 获取显示列结束的位置
     */
    private int getDisplayColumnEnd() {
        int columnPre = 0;
        for (int column = 0; column < mLayoutState.mEachColumnWidthList.size(); column++) {
            int itemLeft = columnPre;
            if (itemLeft >= mLayoutState.mSlideAreaRect.right) {
                return column;
            }
            columnPre += mLayoutState.mEachColumnWidthList.get(column);
        }
        return mLayoutState.mEachColumnWidthList.size() - 1;
    }

    /**
     * 计算平铺出来的宽度和高度
     */
    private void calculateSpreadSize(RecyclerView.Recycler recycler) {
        if (getItemCount() <= 0) {
            return;
        }
        mLayoutState.mSpreadHeight = 0;
        mLayoutState.mSpreadWidth = 0;
        // 平铺高度
        if (mBuild.mFixHeader) {
            mLayoutState.mSpreadHeight = mBuild.mHeadHeight;
            if (mLayoutState.mRowCount > 1) {
                mLayoutState.mSpreadHeight += (mLayoutState.mRowCount - 1) * mBuild.mRowHeight;
            }
        } else {
            mLayoutState.mSpreadHeight = mLayoutState.mRowCount * mBuild.mRowHeight;
        }

        //计算前面固定的列数
        if (mBuild.mFixColumnCount <= 0) {
            mBuild.mFixColumnCount = 0;
        }
        if (mBuild.mFixColumnCount > mBuild.mColumnCount) {
            mBuild.mFixColumnCount = mBuild.mColumnCount;
        }
        if (mBuild.mWidgetCount <= 0) {
            mBuild.mWidgetCount = 0;
        }
        // 平铺宽度   总行数 》 1
        if (mLayoutState.mRowCount > 1) {
            //叠加固定的宽度
            for (int column = 0; column < mBuild.mFixColumnCount; column++) {
                View view = recycler.getViewForPosition(column);
                measureChildWithMargins(view, 0, 0);
                int width = getDecoratedMeasuredWidth(view);
                mLayoutState.mSpreadWidth += width;
                mLayoutState.mEachColumnWidthList.put(column, width);
            }
            //叠加剩下的宽度
            if (mBuild.mWidgetCount == 0 || mBuild.mWidgetCount < (mBuild.mColumnCount - mBuild.mFixColumnCount)) {
                for (int column = mBuild.mFixColumnCount; column < mBuild.mColumnCount; column++) {
                    View view = recycler.getViewForPosition(column);
                    measureChildWithMargins(view, 0, 0);
                    int width = getDecoratedMeasuredWidth(view);
                    mLayoutState.mSpreadWidth += width;
                    mLayoutState.mEachColumnWidthList.put(column, width);
                }
            } else {
                int widgetCount = Math.min(mBuild.mColumnCount - mBuild.mFixColumnCount, mBuild.mWidgetCount);
                if (widgetCount > 0) {
                    float eachWidgetWidth = (getHorizontalActiveWidth() - mLayoutState.mSpreadWidth) * 1.0f / widgetCount;
                    for (int column = mBuild.mFixColumnCount; column < mBuild.mColumnCount; column++) {
                        mLayoutState.mSpreadWidth += eachWidgetWidth;
                        mLayoutState.mEachColumnWidthList.put(column, (int) eachWidgetWidth);
                    }
                }
            }
        } else {
            for (int column = 0; column < mBuild.mFixColumnCount && column < getItemCount(); column++) {
                View view = recycler.getViewForPosition(column);
                measureChildWithMargins(view, 0, 0);
                int width = getDecoratedMeasuredWidth(view);
                mLayoutState.mSpreadWidth += width;
                mLayoutState.mEachColumnWidthList.put(column, width);
            }
            if (mBuild.mWidgetCount == 0 || mBuild.mWidgetCount < (getItemCount() - mBuild.mFixColumnCount)) {
                for (int column = mBuild.mFixColumnCount; column < getItemCount(); column++) {
                    View view = recycler.getViewForPosition(column);
                    measureChildWithMargins(view, 0, 0);
                    int width = getDecoratedMeasuredWidth(view);
                    mLayoutState.mSpreadWidth += width;
                    mLayoutState.mEachColumnWidthList.put(column, width);
                }
            } else {
                int widgetCount = Math.min(getItemCount() - mBuild.mFixColumnCount, mBuild.mWidgetCount);
                if (widgetCount > 0) {
                    float eachWidgetWidth = (getHorizontalActiveWidth() - mLayoutState.mSpreadWidth) * 1.0f / widgetCount;
                    for (int column = mBuild.mFixColumnCount; column < getItemCount(); column++) {
                        mLayoutState.mSpreadWidth += eachWidgetWidth;
                        mLayoutState.mEachColumnWidthList.put(column, (int) eachWidgetWidth);
                    }
                }
            }

        }
    }


    /**
     * 平铺宽度大于内容宽度，水平可以滑动
     */
    @Override
    public boolean canScrollHorizontally() {
        return mLayoutState.mSpreadWidth > getHorizontalActiveWidth();
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        // 先移除所有view
//        detachAndScrapAttachedViews(recycler);
        if (mLayoutState.mOffsetHorizontal + dx > mLayoutState.mSpreadWidth - getHorizontalActiveWidth()) {
            dx = mLayoutState.mSpreadWidth - getHorizontalActiveWidth() - mLayoutState.mOffsetHorizontal;
        } else if (mLayoutState.mOffsetHorizontal + dx < 0) {
            dx = -mLayoutState.mOffsetHorizontal;
        }
        mLayoutState.mOffsetHorizontal += dx;
        mLayoutState.mSlideAreaRect.offset(dx, 0);
        fillChildren(recycler, state);
        return dx;
    }

    /**
     * 平铺的高度大于内容区域的高度，垂直可以滑动
     */
    @Override
    public boolean canScrollVertically() {
        return mLayoutState.mSpreadHeight > getVerticalActiveHeight();
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        // 先移除所有view
        detachAndScrapAttachedViews(recycler);
        if (mLayoutState.mOffsetVertical + dy > mLayoutState.mSpreadHeight - getVerticalActiveHeight()) {
            dy = mLayoutState.mSpreadHeight - getVerticalActiveHeight() - mLayoutState.mOffsetVertical;
        } else if (mLayoutState.mOffsetVertical + dy < 0) {
            dy = -mLayoutState.mOffsetVertical;
        }
        mLayoutState.mOffsetVertical += dy;
        mLayoutState.mSlideAreaRect.offset(0, dy);
        fillChildren(recycler, state);
        return dy;
    }

    private int getHorizontalActiveWidth() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }

    private int getVerticalActiveHeight() {
        return getHeight() - getPaddingTop() - getPaddingBottom();
    }

    public boolean isColumnStart(int position) {
        return position % mLayoutState.mColumnCount == 0;
    }

    public boolean isColumnEnd(int position) {
        return position % mLayoutState.mColumnCount == mLayoutState.mColumnCount - 1;
    }

    public boolean isRowStart(int position) {
        return position < mLayoutState.mColumnCount;
    }

    public boolean isRowEnd(int position) {
        return position >= (mLayoutState.mRowCount - 1) * mLayoutState.mColumnCount;
    }

    /**
     * the layout state of the LayoutManager
     */
    private static class LayoutState {

        /**
         * 总行数
         */
        int mRowCount;
        /**
         * 总列数
         */
        int mColumnCount;
        /**
         * 整个平铺开来，总宽度
         */
        int mSpreadWidth;
        /**
         * 整个平铺开来，总高度
         */
        int mSpreadHeight;
        /**
         * 每一列对应的宽度list
         */
        SparseIntArray mEachColumnWidthList;
        /**
         * 水平偏移量
         */
        int mOffsetHorizontal;
        /**
         * 垂直偏移量
         */
        int mOffsetVertical;
        /**
         * 内容区域(可滑动的区域),绘制的时候只绘制内容区域内的item
         */
        Rect mSlideAreaRect;

        LayoutState() {
            reset();
        }

        void reset() {
            mSpreadWidth = 0;
            mSpreadHeight = 0;
            mOffsetHorizontal = 0;
            mOffsetVertical = 0;
            mSlideAreaRect = new Rect();
            mEachColumnWidthList = new SparseIntArray();
        }
    }


    public static class Build {

        /**
         * 表格列数
         */
        int mColumnCount;
        /**
         * 是否固定表头
         */
        boolean mFixHeader;
        /**
         * 表头行高度
         */
        int mHeadHeight;
        /**
         * 表每一行的高度
         */
        int mRowHeight;
        /**
         * 每一行的前多少列固定不动
         */
        int mFixColumnCount;
        /**
         * 当非固定的列小于这个时候，自动平分屏幕(类似于LinearLayout widget效果)
         */
        int mWidgetCount;

        Build(Context context) {
            mColumnCount = 1;
            mFixHeader = false;
            mHeadHeight = DensityUtils.dp2px(context, 48);
            mRowHeight = DensityUtils.dp2px(context, 48);
            mFixColumnCount = 0;
            mWidgetCount = 0;
        }

        public Build setColumnCount(int columnCount) {
            mColumnCount = columnCount;
            return this;
        }

        public Build setFixHeader(boolean fixed) {
            mFixHeader = fixed;
            return this;
        }

        public Build setHeadHeight(int height) {
            mHeadHeight = height;
            return this;
        }

        public Build setRowHeight(int height) {
            mRowHeight = height;
            return this;
        }

        public Build setFixColumnCount(int count) {
            mFixColumnCount = count;
            return this;
        }

        public Build setWidgetCount(int widgetCount) {
            mWidgetCount = widgetCount;
            return this;
        }

        TableLayoutManager build() {
            return new TableLayoutManager(this);
        }

    }

    public static class LayoutParams extends RecyclerView.LayoutParams {

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(ViewGroup.MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

        public LayoutParams(RecyclerView.LayoutParams source) {
            super(source);
        }
    }


}
